package cn.sjx.print.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.http.HtmlUtil;
import cn.sjx.print.constants.PrintConstant;
import cn.sjx.print.entity.HtmlRenderData;
import cn.sjx.print.util.SpringContextHolder;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRMapCollectionDataSource;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 基础打印渲染工具类
 *
 * @Author: sjx
 * @Date: 2020年09月10日 0010 07:41:34
 */
public class BaseRenderFactoryHandler {

    /**
     * 创建JasperPrint对象
     *
     * @param templateName    模板名称
     * @param htmlRenderData  填充数据（若dataList为空，则采用druid数据源）
     * @param subTemplateName 子模板名称（在jasperReport中，添加相同个数名称为“SUB_REPORT_[0，1，2......]”；Class属性为“net.sf.jasperreports.engine.JasperReport”的Parameters参数）
     * @return {@link JasperPrint }
     * @throws Exception 异常
     */
    protected static JasperPrint generateJasperPrint(String templateName,
                                                     HtmlRenderData htmlRenderData,
                                                     String... subTemplateName) throws Exception {
        if (null == htmlRenderData) {
            throw new Exception("模板渲染数据不能为空！");
        }

        Map<String, Object> parametersMap = htmlRenderData.getParamMap();
        List<Map<String, ?>> dataList = htmlRenderData.getDataList();

        // 参数不为空,进行反转义处理
        if (MapUtil.isNotEmpty(parametersMap) &&
                PrintConstant.PRINT_CONFIG_SETTING.getBool(PrintConstant.PRINT_CONFIG_PRINT_DATA_UNESCAPE)) {
            String parametersMapStr = JSON.toJSONString(parametersMap);
            parametersMap = JSON.parseObject(HtmlUtil.unescape(parametersMapStr), new TypeReference<Map<String, Object>>() {
            }.getType());
        }

        if (CollUtil.isNotEmpty(dataList) &&
                PrintConstant.PRINT_CONFIG_SETTING.getBool(PrintConstant.PRINT_CONFIG_PRINT_DATA_UNESCAPE)) {
            String dataListStr = JSON.toJSONString(dataList);
            dataList = JSON.parseObject(HtmlUtil.unescape(dataListStr), new TypeReference<List<Map<String, ?>>>() {
            }.getType());
        }

        // region 1. 获取jasperReport主模板，并编译
        InputStream jasperStream = ResourceUtil.getStream(PrintConstant.TEMPLATE_FILE_PREFIX +
                templateName + PrintConstant.TEMPLATE_FILE_SUFFIX);
        JasperReport jasperReport = JasperCompileManager.compileReport(jasperStream);
        jasperStream.close();

        // 1.1 获取子模板数据
        if (ArrayUtil.isNotEmpty(subTemplateName)) {
            for (int i = 0; i < subTemplateName.length; i++) {
                /*
                // 方法1：直接使用编译好的文件
                InputStream subReportInputStream = ResourceUtil.getStream(TEMPLATE_FILE_PREFIX + subTemplateName[i] + TEMPLATE_BUILD_FILE_SUFFIX);
                JasperReport subReport = (JasperReport) JRLoader.loadObject(subReportInputStream);
                */
                InputStream subReportInputStream = ResourceUtil.getStream(PrintConstant.TEMPLATE_FILE_PREFIX +
                        subTemplateName[i] + PrintConstant.TEMPLATE_FILE_SUFFIX);
                JasperReport subReport = JasperCompileManager.compileReport(subReportInputStream);
                parametersMap.put("SUB_REPORT_" + i, subReport);
                subReportInputStream.close();
            }
        }

        // endregion

        // region 2. 填充模版内容
        JasperPrint jasperPrint = null;

        switch (htmlRenderData.getMode()) {
            case DATA_FROM_DB:

                // 获取druid数据源连接
                DruidDataSource dataSource = SpringContextHolder.getBean("dataSource", DruidDataSource.class);
                if (null == dataSource) {
                    throw new Exception("dataSource获取失败！");
                }
                DruidPooledConnection connection = dataSource.getConnection();

                // 填充数据
                jasperPrint = JasperFillManager.fillReport(jasperReport,
                        MapUtil.defaultIfEmpty(parametersMap, new HashMap<String, Object>(0)),
                        connection);

                if (null != connection) {
                    connection.close();
                }
                break;
            case DATA_FROM_COLLECTION_MAP:

                // 用传入的 List<Map<String, ?> 构造数据源
                JRDataSource jrDataSource = null;
                if (CollectionUtil.isEmpty(dataList)) {
                    // dataList为空，传入空数据源
                    jrDataSource = new JREmptyDataSource();
                } else {
                    // region 数据反转义处理
                    if (PrintConstant.PRINT_CONFIG_SETTING.getBool(PrintConstant.PRINT_CONFIG_PRINT_DATA_UNESCAPE)) {
                        String dataListStr = JSON.toJSONString(dataList);
                        dataList = JSON.parseObject(HtmlUtil.unescape(dataListStr),
                                new TypeReference<List<Map<String, ?>>>() {
                                }.getType());
                    }
                    // endregion 数据反转义处理
                    jrDataSource = new JRMapCollectionDataSource(dataList);
                }

                // 填充数据
                jasperPrint = JasperFillManager.fillReport(jasperReport,
                        MapUtil.defaultIfEmpty(parametersMap, new HashMap<String, Object>(0)),
                        jrDataSource);

                break;
            case DATA_FROM_EMPTY:
            default:

                // 填充数据
                jasperPrint = JasperFillManager.fillReport(jasperReport,
                        MapUtil.defaultIfEmpty(parametersMap, new HashMap<String, Object>(0)),
                        new JREmptyDataSource());
        }
        // endregion

        return jasperPrint;
    }

}